rz#include <SPI.h>

#define VERSION         "1.0"
#define IDENT           "EEPROM29_595"

//数据
#define Data0 PIN_PC0
#define Data1 PIN_PC1
#define Data2 PIN_PD2
#define Data3 PIN_PD3
#define Data4 PIN_PD4
#define Data5 PIN_PD5
#define Data6 PIN_PD6
#define Data7 PIN_PD7

//595控制
#define DS    PIN_PB3 //数据位
#define LATCH PIN_PB2
#define SCK   PIN_PB5

#define chipWE PIN_PB0
#define chipCE PIN_PB1
#define chipOE PIN_PC5

#define A_16  PIN_PC2
#define A_17  PIN_PC3
#define A_18  PIN_PC4

#define delay125ns      {asm volatile("nop"); asm volatile("nop");}

// Buffers
#define BUFF_LEN 128
#define CMD_LEN 22

uint8_t pageBuffer[BUFF_LEN];                  // page buffer
char    cmdBuffer[CMD_LEN];                    // command buffer

void read_mode(void){
  pinMode(Data0, INPUT);
  pinMode(Data1, INPUT);
  pinMode(Data2, INPUT);
  pinMode(Data3, INPUT);
  pinMode(Data4, INPUT);
  pinMode(Data5, INPUT);
  pinMode(Data6, INPUT);
  pinMode(Data7, INPUT);
}

void write_mode(void){
  pinMode(Data0, OUTPUT);
  pinMode(Data1, OUTPUT);
  pinMode(Data2, OUTPUT);
  pinMode(Data3, OUTPUT);
  pinMode(Data4, OUTPUT);
  pinMode(Data5, OUTPUT);
  pinMode(Data6, OUTPUT);
  pinMode(Data7, OUTPUT);
}



// 读取数据
uint8_t read_data_bus(void) {
  return ((digitalRead(Data7) << 7) +
          (digitalRead(Data6) << 6) +
          (digitalRead(Data5) << 5) +
          (digitalRead(Data4) << 4) +
          (digitalRead(Data3) << 3) +
          (digitalRead(Data2) << 2) +
          (digitalRead(Data1) << 1) +
          digitalRead(Data0));
}

void write_data_bus(byte data){
  digitalWrite(Data0, data & 1);//也可使用移位 data & (1 << 0)
  digitalWrite(Data1, data & 2);
  digitalWrite(Data2, data & 4);
  digitalWrite(Data3, data & 8);
  digitalWrite(Data4, data & 16);
  digitalWrite(Data5, data & 32);
  digitalWrite(Data6, data & 64);
  digitalWrite(Data7, data & 128);
}
void setAddress(uint32_t addr) {
  digitalWrite(A_16, (addr >> 16) & 1);
  digitalWrite(A_17, (addr >> 17) & 1);
  digitalWrite(A_18, (addr >> 18) & 1);
  
//  uint8_t h = addr>>8 & 0xff;
//  uint8_t l = addr & 0xff;
//  SPI.transfer (h);
//  SPI.transfer (l);

  SPI.transfer16(addr & 0xffff);
  
  digitalWrite(LATCH, LOW);
  digitalWrite(LATCH, HIGH);
  digitalWrite(LATCH, LOW);
}

void chip29(){
  digitalWrite(chipWE, HIGH);
}

void setup() {
  read_mode();
  //初始化
  pinMode(DS, OUTPUT);
  pinMode(SCK, OUTPUT);
  pinMode(LATCH, OUTPUT);
  digitalWrite(DS, LOW);
  digitalWrite(SCK, LOW);
  digitalWrite(LATCH, HIGH);
  SPI.begin();
  SPI.setClockDivider(SPI_CLOCK_DIV2);
//   SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));

  //地址线
  pinMode(A_16, OUTPUT);
  pinMode(A_17, OUTPUT);
  pinMode(A_18, OUTPUT);
  digitalWrite(A_16,HIGH);
  digitalWrite(A_17,HIGH);
  digitalWrite(A_18,HIGH);
  
  pinMode(chipWE, OUTPUT);
  pinMode(chipCE, OUTPUT);
  pinMode(chipOE, OUTPUT);
  digitalWrite(chipWE,HIGH);
  digitalWrite(chipCE,HIGH);
  digitalWrite(chipOE,HIGH);

  // 初始化地址
  setAddress(0);
  
//  Serial.begin(1000000);
  Serial.begin(115200);
}

const uint8_t chip_size = 6;
const uint32_t chips[chip_size] = {
  29010,29020,29040,
  29011,29021,29041,
};

//是否支持
boolean chipSupport(uint32_t chipId){
  for(int i=0;i<chip_size;i++){
    if(chips[i]==chipId)return true;
  }
  return false;
}

void check(uint32_t chipId){
  if(chipSupport(chipId)){
    Serial.println(F("ok"));
  }else{
    Serial.println(F("Check chip unsupport"));
  }
}

void loop() {
  //程序判断用
  Serial.println("Ready");
  
  readCommand();
  char cmd = cmdBuffer[0];                      //指令
  uint32_t chipId    = hexChip(cmdBuffer + 2);  //芯片
  uint8_t  startPage = hexDigit(cmdBuffer[9]);
  uint32_t startAddr = hexWord(cmdBuffer + 10); //开始地址
  uint8_t  endPage   = hexDigit(cmdBuffer[15]);
  uint32_t endAddr   = hexWord(cmdBuffer + 16); //结束地址

  startAddr &= 0xffff;
  endAddr &= 0xffff;
  startPage &= 0x7;
  endPage   &= 0x7;
  endPage = endPage < startPage ? startPage : endPage;

  startAddr = (startPage * 65536) + startAddr;
  endAddr   = (endPage * 65536) + endAddr;

  endAddr = endAddr < startAddr ? startAddr : endAddr;

  // 数据长度
  uint32_t dataLength = endAddr - startAddr + 1;

  // 初始化地址
  setAddress(0);

  switch(cmd) {
    case 'i':   Serial.println(IDENT); break;
    case 'v':   Serial.println(VERSION); break;
    //测试输入内容
    case 'r':   read29(startAddr, dataLength); break;
    case 'w':   
      if (chipId==2716||chipId==2732) { //27-24p
      } else if (chipId==2764||chipId==27128||chipId==27256) { //27-28p
      } else if (chipId==2864||chipId==28256) { //28
      } else if (chipId==29011||chipId==29021||chipId==29041) { //29
        //winbond
        write29(startAddr, dataLength, 9);
      } else if (chipId==29010||chipId==29020||chipId==29040) { //29
        write29(startAddr, dataLength, 29);
      } else {
        Serial.print(F("Write not support,chipId:"));
        Serial.println(chipId);
      }
      break;

    case 'c':   check(chipId); break;
    
    case 'u':   disableWriteProtection29(); break;
    case 'l':   enableWriteProtection29(); break;
    //29芯片擦除指令
    case 'e':   eraser29(); break;
    
    case 'x':   Serial.print(startAddr);Serial.print(" ");Serial.print(endAddr); Serial.print(" ");Serial.println(dataLength); break;
    default:    break;
  }
}

// 读取芯片内容(读取的时候ce oe全部拉低，改变地址就可以输出)
void read29(uint32_t addr, uint32_t count) {
  //加上y参数的扩展地址
  read_mode();
  digitalWrite(chipWE, HIGH);
  digitalWrite(chipCE, LOW);
  digitalWrite(chipOE, LOW);
  setAddress(0);
  
  while (count-- >0) {
    Serial.write(getByte(addr++));
    if(addr & 0xfff ==0)delay(1);
  }
  digitalWrite(chipOE, HIGH);
  digitalWrite(chipCE, HIGH);
}

void write29(uint32_t addr, uint32_t total, uint8_t type) {
  for (uint8_t i = 0; i < BUFF_LEN; i++) {
    while (!Serial.available());
    pageBuffer[i] = Serial.read();
  }

  chip29();

  write_mode();
  digitalWrite(chipOE, HIGH);
  digitalWrite(chipWE, HIGH);

  // A29 MX29 SSF39
  if (type == 29 || type == 39) {
    digitalWrite(chipCE, LOW);
    delayMicroseconds(1);

    if(addr==0){
      for (uint8_t i = 0; i < BUFF_LEN; i++) {
        setByte (0x5555, 0xaa);
        setByte (0x2aaa, 0x55);
        setByte (0x5555, 0xa0);
        setByte (addr+i, pageBuffer[i]);
      }
    }
    
    for (uint8_t i = 0; i < BUFF_LEN; i++) {
      setByte (0x5555, 0xaa);
      setByte (0x2aaa, 0x55);
      setByte (0x5555, 0xa0);
      setByte (addr+i, pageBuffer[i]);
    }
    // Winbond 29 特殊的 128 字节写入
  } else if (type == 9) {
    digitalWrite(chipCE, LOW);
    setByte (0x5555, 0xaa);
    setByte (0x2aaa, 0x55);
    setByte (0x5555, 0xa0);
    for (uint8_t i = 0; i < BUFF_LEN; i++) {
      setByte(addr+i, pageBuffer[i]);
    }
    delay(10);
    // 其他芯片报错
  } else {
    Serial.print(F("Not support type for write:"));
    Serial.println(type);
    return;
  }

  digitalWrite(chipWE, HIGH);
  digitalWrite(chipOE, HIGH);
  digitalWrite(chipCE, HIGH);
  delayMicroseconds(35);

  check_buff29(addr,type);
}

void check_buff29(uint32_t addr,uint8_t type){
  
  read_mode();
  //读数据校验
  digitalWrite(chipWE, HIGH);
  digitalWrite(chipCE, LOW);
  digitalWrite(chipOE, LOW);
  delayMicroseconds(10);
  boolean has_error = false;
  for(int i=0;i<BUFF_LEN ;i++){
    uint8_t rd = getByte(addr+i);
    if(pageBuffer[i]!=rd){
      Serial.print("0x");
      Serial.print(addr+i,HEX);
      Serial.print("=");
      Serial.print(rd,HEX);
      Serial.print(",not:");
      Serial.print(pageBuffer[i],HEX);
      Serial.print(" ");
      has_error = true;
    }
  }
  if(has_error){
    Serial.print("_type:");
    Serial.print(type);
  }
  digitalWrite(chipCE, HIGH);
  digitalWrite(chipOE, HIGH);
}

// 28 29
void setByte(uint32_t address, uint8_t data){
  write_data_bus(data);
  setAddress(address);
  delayMicroseconds(1);
  digitalWrite(chipWE, LOW);
  delayMicroseconds(1);
  digitalWrite(chipWE, HIGH);
}
// 根据地址读取数据
byte getByte(uint32_t addr) {
  setAddress (addr);
  delayMicroseconds(1);
  return read_data_bus();
}

// write the special six-byte code to turn off software data protection
void disableWriteProtection29() {
  digitalWrite(chipCE, LOW);
  write_mode();                            // set data bus pins as output 
  //reset
  setByte (0x0000, 0xf0);
  delayMicroseconds(1);
  setByte (0x5555, 0xaa);                     // write code sequence
  setByte (0x2aaa, 0x55);
  setByte (0x5555, 0x80);
  setByte (0x5555, 0xaa);
  setByte (0x2aaa, 0x55);
  setByte (0x5555, 0x20);
  digitalWrite(chipCE, LOW);
  read_mode();                             // release data bus (set as input)
  delay(10);                                  // wait write cycle time
  Serial.println("ok");
}

// write the special three-byte code to turn on software data protection
void enableWriteProtection29() {
  digitalWrite(chipCE, LOW);
  write_mode();                            // set data bus pins as output
  //reset
  setByte (0x0000, 0xf0);
  delayMicroseconds(1);
  setByte (0x5555, 0xaa);                     // write code sequence
  setByte (0x2aaa, 0x55);
  setByte (0x5555, 0xa0);
  digitalWrite(chipCE, HIGH);
  read_mode();                             // release data bus (set as input)
  delay(10);                                  // wait write cycle time
}

void eraser29() {
  digitalWrite(chipOE, HIGH);
  digitalWrite(chipCE, LOW);
  write_mode();                            // set data bus pins as output
  //reset
  setByte (0x0000, 0xf0);
  delayMicroseconds(1);
  setByte (0x5555, 0xaa);                     // write code sequence
  setByte (0x2aaa, 0x55);
  setByte (0x5555, 0x80);
  setByte (0x5555, 0xaa);
  setByte (0x2aaa, 0x55);
  setByte (0x5555, 0x10);
  delay(1);
  digitalWrite(chipCE, HIGH);
  read_mode();                             // release data bus (set as input)
  delay(10);                                  // wait write cycle time
}


void readCommand() {
  for(uint8_t i=0; i< CMD_LEN; i++) cmdBuffer[i] = 0;  // clear command buffer
  char c; uint8_t idx = 0;                        // initialize variables
  do {
    if(Serial.available()) {
      c = Serial.read();
      cmdBuffer[idx++] = c;
    }
  } while (c != '\n' && idx < CMD_LEN);
  cmdBuffer[idx - 1] = 0;                     // change last newline to '\0' termination
}

// 返回字芯片字符串
uint32_t hexChip(char* data) {
  uint32_t re = 0;
//  if (data[0] >= 0x30 && data[0] <= 0x39)re += (data[0] - 0x30) * 100000;
  if (data[1] >= 0x30 && data[1] <= 0x39)re += (data[1] - 0x30) * 10000;
  if (data[2] >= 0x30 && data[2] <= 0x39)re += (data[2] - 0x30) * 1000;
  if (data[3] >= 0x30 && data[3] <= 0x39)re += (data[3] - 0x30) * 100;
  if (data[4] >= 0x30 && data[4] <= 0x39)re += (data[4] - 0x30) * 10;
  if (data[5] >= 0x30 && data[5] <= 0x39)re += (data[5] - 0x30) * 1;
  return re;
}

// converts character representing a hex nibble into 4-bit value
uint8_t hexDigit(char c) {
  if      (c >= '0' && c <= '9') return c - '0';
  else if (c >= 'a' && c <= 'f') return c - 'a' + 10;
  else if (c >= 'A' && c <= 'F') return c - 'A' + 10;
  else return 0;
}


// converts string containing a hex byte into 8-bit value
byte hexByte(char* a) {
  return ((hexDigit(a[0])*16) + hexDigit(a[1]));
}


// converts string containing a hex word into 16-bit value
uint16_t hexWord(char* data) {
  return ((hexDigit(data[0])*4096)+
    (hexDigit(data[1])*256)+
    (hexDigit(data[2])*16)+
    (hexDigit(data[3])));
}
